package java01;

import org.junit.Test;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;

public class JavaGenericAndBox {

    @Test
    public void genericTest01(){
        ArrayList<String> list = new ArrayList<>(50);//管理一个内置数组，如果内置数组被填满，就会创建一个更大的数组将所有数据拷贝至其中，可在创建时预分配空间
        list.ensureCapacity(100);//如果预知数组大小，可以调用该方法预分配一个100对象容量内部数组，100次存储操作不会重新分配空间
        list.add("aaa");
        list.add("x");
        list.add(2,"ccc");//从中间插入元素，该位后的所有元素都会向后移一位
        list.set(1,"bbb");
        list.trimToSize();//一旦确定数组列表大小不再发生变化，可以调用该方法将存储大小调整为当前元素数量所需空间大小，垃圾回收器将回收多余空间
    }

    @Test
    public void autoBox(){
        Number number= 1.1;//包装器类的公共类
        Float v = number.floatValue();//一旦构造了包装器，就不允许改变其中的值
        System.out.println(v);
        //由于每个值被分别包装在对象中，ArrayList<Integer>的效率远远低于int[]数组
        ArrayList<Integer> arr = new ArrayList<>();
        arr.add(3);//自动装箱：自动变成arr.add(Integer.valueOf(3));
        int x = arr.get(0);//自动拆箱：自动变成arr.get(0).intValue();
        System.out.println(x);
        Integer y=1000;
        Integer z=1000;
        if(y==z){
            System.out.println("==比较:<-128 and >127"+true);//false
        }
        y=127;
        z=127;
        if(y==z){
            System.out.println("-128~127"+true);//true
        }
        //自动装箱要求boolean、byte、char<=127、介于-128~127之间的同short和int才会被包装到固定的对象中（一个存储地址），才能够用==来比较。
        // 否则就得用equals比较才可解决该问题。
        if(y.equals(z)){
            System.out.println("equals比较:<-128 and >127"+true);//true
        }
        //包装类可以为null，有可能会报空指针异常
        Double d=6.6;
        System.out.println(true?y:d);
        //过程：Integer自动拆箱为int，提升为double，再装箱为Double
        //最后：装箱和拆箱是编译器认可的，不是虚拟机
    }

    //@SafeVarargs注解，对于非static或非final声明的方法，不适用，会编译不通过
    //在声明具有模糊类型（比如：泛型）的可变参数的构造函数或方法时，Java编译器会报unchecked警告。
    // 鉴于这些情况，如果程序员断定声明的构造函数和方法的主体不会对其varargs参数执行潜在的不安全的操作，可使用@SafeVarargs进行标记
    @SafeVarargs                     //限定类型用&分隔
    public final <T extends Comparable<T> & Serializable> T[] genericMethod(T... t){//用<T extends Comparable<T>>来确定传入的变量有CompareTo方法，表示T应该绑定类型的子类型
        System.out.println(t[0]+":"+t[1]+":"+t[2]);
        Arrays.sort(t);
        return t;
    }

    public static void main(String[] args) {
        JavaGenericAndBox javaGenericAndBox = new JavaGenericAndBox();
        String[] str = javaGenericAndBox.genericMethod("222", "122", "333", "999", "444");
        System.out.println(Arrays.toString(str));
        Generic<Parent>[] generics = new Generic[10];//不能声明参数化类型数组，new Generic<String>[10]
        generics[0]= new Generic<>();
        Generic<String>[] generic = (Generic<String>[]) new Generic<?>[10];//可以声明通配类型数组，然后进行强制类型转换,但其结果将是不安全的
//        ArrayList<Generic<String>>如果要收集参数化类型对象，只有该种有效方法。数组不支持泛型类型
    }
}
